
import sys, time

import asyncore, asynchat, socket, sys ,threading, os , os.path,traceback, time , base64 
import re, urllib, urlparse
import httplib
import Queue
from Foundation import *
import objc
import signal
from owa import *
from settings import *
from macstuff import *
import pickle
objc.setVerbose(1)
__version__ = 'OWA WRAPPER 0.0.1'
pool  = NSAutoreleasePool.alloc().init()
class OSMTPServer(smtpd.SMTPServer, MacLog):
	def __init__(self):
		self.port = 8025
		self.config = None
		self.clog('Init')
		self.loadSettings()
		self.clog('Loaded Settings')
		address = ('127.0.0.1',self.port)
		smtpd.SMTPServer.__init__(self,address,None)
	
	def handle_accept(self):
		conn, addr = self.accept()
		self.cdebug ( 'Incoming connection from %s' % repr(addr))
		channel = SMTPChannel(self, conn, addr)

	def loadSettings(self):
		self.config = loadData(SETTINGS_FILE)
		if not self.config:
			self.config = DEFAULT_SETTINGS
		try:
			LOGLEVEL = self.config['smtplevel']
			self.clog('level: '+repr(LOGLEVEL))

			self.port = self.config['smtpport']
			self.clog('Port: '+repr(self.port))
		except:
			pass
		
class SMTPChannel(asynchat.async_chat,MacLog):
	COMMAND = 0
	DATA = 1

	def __init__(self, server, conn, addr):
		asynchat.async_chat.__init__(self, conn)
		self.__server = server
		self.__conn = conn
		self.__addr = addr
		self.__line = []
		self.__state = self.COMMAND
		self.__greeting = 0
		self.__mailfrom = None
		self.__rcpttos = []
		self.__data = ''
		self.__fqdn = socket.gethostbyaddr(
			socket.gethostbyname(socket.gethostname()))[0]
		self.__peer = conn.getpeername()
		self.clog('Peer:'+ repr(self.__peer))
		self.push('220 %s %s' % (self.__fqdn, __version__))
		self.set_terminator('\r\n')

	def push(self, msg):
		self.cdebug('>' + msg)
		asynchat.async_chat.push(self, msg + '\r\n')

	def collect_incoming_data(self, data):
		self.cdebug( '<' + data)
		self.__line.append(data)


	def found_terminator(self):
		line = ''.join(self.__line)
		self.__line = []
		if self.__state == self.COMMAND:
			if not line:
				self.push('500 Error: bad syntax')
				return
			method = None
			i = line.find(' ')
			if i < 0:
				command = line.upper()
				arg = None
			else:
				command = line[:i].upper()
				arg = line[i+1:].strip()
			method = getattr(self, 'smtp_' + command, None)
			if not method:
				self.push('502 Error: command "%s" not implemented' % command)
				return
			method(arg)
			return
		else:
			if self.__state <> self.DATA:
				self.push('451 Internal confusion')
				return
			# Remove extraneous carriage returns and de-transparency according
			# to RFC 821, Section 4.5.2.
			data = []
			for text in line.split('\r\n'):
				if text and text[0] == '.':
					data.append(text[1:])
				else:
					data.append(text)
			subject = ''
			
			for l in data:
				if l.startswith('Subject'):
					subject = l.split(": ")[1]
			
			#print "Subject:" , subject
			
				
			
			
			#msg = email.message_from_string(data)
			
			status, reason,html,hdrs = self.owa.sendMessage(subject,line)
			#self.__server.process_message(self.__peer,
						#							self.__mailfrom,
						#							self.__rcpttos,
						#							self.__data)
			self.__rcpttos = []
			self.__mailfrom = None
			self.__state = self.COMMAND
			self.set_terminator('\r\n')
			if not status:
				self.push('250 Ok')
			else:
				self.push(str(status))

	# SMTP and ESMTP commands
	def smtp_EHLO(self,arg):
		return self.smtp_HELO(arg)
	
	def smtp_HELO(self, arg):
		if not arg:
			self.push('501 Syntax: HELO hostname')
			return
		if self.__greeting:
			self.push('503 Duplicate HELO/EHLO')
		else:
			self.__greeting = arg
			self.push('250-%s' % self.__fqdn)
			self.push('250 AUTH LOGIN PLAIN')
			

	def smtp_NOOP(self, arg):
		if arg:
			self.push('501 Syntax: NOOP')
		else:
			self.push('250 Ok')

	def smtp_QUIT(self, arg):
		# args is ignored
		self.push('221 Bye')
		self.close_when_done()

	# factored
	def __getaddr(self, keyword, arg):
		address = None
		keylen = len(keyword)
		if arg[:keylen].upper() == keyword:
			address = arg[keylen:].strip()
			if address[0] == '<' and address[-1] == '>' and address <> '<>':
				# Addresses can be in the form <person@dom.com> but watch out
				# for null address, e.g. <>
				address = address[1:-1]
		return address

	def smtp_MAIL(self, arg):
		#print  '===> MAIL', arg
		address = self.__getaddr('FROM:', arg)
		if not address:
			self.push('501 Syntax: MAIL FROM:<address>')
			return
		if self.__mailfrom:
			self.push('503 Error: nested MAIL command')
			return
		self.__mailfrom = address
		#print  'sender:', self.__mailfrom
		self.push('250 Ok')

	def smtp_RCPT(self, arg):
		#print  '===> RCPT', arg
		if not self.__mailfrom:
			self.push('503 Error: need MAIL command')
			return
		address = self.__getaddr('TO:', arg)
		if not address:
			self.push('501 Syntax: RCPT TO: <address>')
			return
		if address.lower().startswith('stimpy'):
			self.push('503 You suck %s' % address)
			return
		self.__rcpttos.append(address)
		#print  'recips:', self.__rcpttos
		self.push('250 Ok')

	def smtp_RSET(self, arg):
		if arg:
			self.push('501 Syntax: RSET')
			return
		# Resets the sender, recipients, and data, but not the greeting
		self.__mailfrom = None
		self.__rcpttos = []
		self.__data = ''
		self.__state = self.COMMAND
		self.push('250 Ok')

	def smtp_DATA(self, arg):
		if not self.__rcpttos:
			self.push('503 Error: need RCPT command')
			return
		if arg:
			self.push('501 Syntax: DATA')
			return
		self.__state = self.DATA
		self.set_terminator('\r\n.\r\n')
		self.push('354 End data with <CR><LF>.<CR><LF>')

	def smtp_AUTH(self, arg):
		
		print arg
		#kind, data = arg.split(" ")
		words = arg.split(" ")
		print words
		# TODO: Ensure kind == "PLAIN"
		# TODO: Support "LOGIN" (required by Outlook?) <http://www.technoids.org/saslmech.html>
		if len(words)<2:
			self.push("535 Authorization failed")
			return
		data = words[1]
		data = base64.decodestring(data)[1:]
		#print "Decoded:" , data
		user, self.password = data.split("\x00")
		#print user, self.password
		self.username , at , self.url = user.partition('@')
		self.owa = OWA(self.url, self.username, self.password)
		try:
			self.owa.login()
			self.push('235 Ok')
		except:
		    self.push("535 Authorization failed")

	

				

		
if __name__ == '__main__':
	print >>sys.stderr, "Starting:"
	pop = OSMTPServer()
	try:
		asyncore.loop()
	except KeyboardInterrupt:
		print >>sys.stderr, "Interrupted:"
		pass
	finally:
		print >>sys.stderr, "Exit:"
		pass
